/**
 * Hilo
 * Copyright 2015 alibaba.com
 * Licensed under the MIT License
 */

/**
 * @class canvas画布渲染器。所有可视对象将渲染在canvas画布上。舞台Stage会根据参数canvas选择不同的渲染器，开发者无需直接使用此类。
 * @augments Renderer
 * @param {Object} properties 创建对象的属性参数。可包含此类所有可写属性。
 * @module hilo/renderer/CanvasRenderer
 * @requires hilo/core/Class
 * @requires hilo/core/Hilo
 * @requires hilo/renderer/Renderer
 * @property {CanvasRenderingContext2D} context canvas画布的上下文。只读属性。
 */
var CanvasRenderer = Class.create( /** @lends CanvasRenderer.prototype */ {
    Extends: Renderer,
    constructor: function(properties) {
        CanvasRenderer.superclass.constructor.call(this, properties);

        this.context = this.canvas.getContext("2d");
    },
    renderType: 'canvas',
    context: null,

    /**
     * @private
     * @see Renderer#startDraw
     */
    startDraw: function(target) {
        if (target.visible && target.alpha > 0) {
            if (target === this.stage) {
                this.context.clearRect(0, 0, target.width, target.height);
            }
            if (target.blendMode !== this.blendMode) {
                this.context.globalCompositeOperation = this.blendMode = target.blendMode;
            }
            this.context.save();
            return true;
        }
        return false;
    },

    /**
     * @private
     * @see Renderer#draw
     */
    draw: function(target) {
        var ctx = this.context,
            w = target.width,
            h = target.height;

        //draw background
        var bg = target.background;
        if (bg) {
            ctx.fillStyle = bg;
            ctx.fillRect(0, 0, w, h);
        }

        //draw image
        var drawable = target.drawable,
            image = drawable && drawable.image;
        if (image) {
            var rect = drawable.rect,
                sw = rect[2],
                sh = rect[3],
                offsetX = rect[4],
                offsetY = rect[5];
            //ie9+浏览器宽高为0时会报错 fixed ie9 bug.
            if (!sw || !sh) {
                return;
            }
            if (!w && !h) {
                //fix width/height TODO: how to get rid of this?
                w = target.width = sw;
                h = target.height = sh;
            }
            //the pivot is the center of frame if has offset, otherwise is (0, 0)
            if (offsetX || offsetY) ctx.translate(offsetX - sw * 0.5, offsetY - sh * 0.5);
            ctx.drawImage(image, rect[0], rect[1], sw, sh, 0, 0, w, h);
        }
    },

    /**
     * @private
     * @see Renderer#endDraw
     */
    endDraw: function(target) {
        this.context.restore();
    },

    /**
     * @private
     * @see Renderer#transform
     */
    transform: function(target) {
        var drawable = target.drawable;
        if (drawable && drawable.domElement) {
            Hilo.setElementStyleByView(target);
            return;
        }

        var ctx = this.context,
            scaleX = target.scaleX,
            scaleY = target.scaleY;

        if (target === this.stage) {
            var style = this.canvas.style,
                oldScaleX = target._scaleX,
                oldScaleY = target._scaleY,
                isStyleChange = false;

            if ((!oldScaleX && scaleX != 1) || (oldScaleX && oldScaleX != scaleX)) {
                target._scaleX = scaleX;
                style.width = scaleX * target.width + "px";
                isStyleChange = true;
            }
            if ((!oldScaleY && scaleY != 1) || (oldScaleY && oldScaleY != scaleY)) {
                target._scaleY = scaleY;
                style.height = scaleY * target.height + "px";
                isStyleChange = true;
            }
            if (isStyleChange) {
                target.updateViewport();
            }
        } else {
            var x = target.x,
                y = target.y,
                pivotX = target.pivotX,
                pivotY = target.pivotY,
                rotation = target.rotation % 360,
                transform = target.transform,
                mask = target.mask;

            if (mask) {
                mask._render(this);
                ctx.clip();
            }

            //alignment
            var align = target.align;
            if (align) {
                var pos = target.getAlignPosition();
                x = pos.x;
                y = pos.y;
            }
            
            if (transform) {
                ctx.transform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty);
            } else {
                if (x != 0 || y != 0) ctx.translate(x, y);
                if (rotation != 0) ctx.rotate(rotation * Math.PI / 180);
                if (scaleX != 1 || scaleY != 1) ctx.scale(scaleX, scaleY);
                if (pivotX != 0 || pivotY != 0) ctx.translate(-pivotX, -pivotY);
            }

        }

        if (target.alpha > 0) ctx.globalAlpha *= target.alpha;
    },

    /**
     * @private
     * @see Renderer#remove
     */
    remove: function(target) {
        var drawable = target.drawable;
        var elem = drawable && drawable.domElement;

        if (elem) {
            var parentElem = elem.parentNode;
            if (parentElem) {
                parentElem.removeChild(elem);
            }
        }
    },

    /**
     * @private
     * @see Renderer#clear
     */
    clear: function(x, y, width, height) {
        this.context.clearRect(x, y, width, height);
    },

    /**
     * @private
     * @see Renderer#resize
     */
    resize: function(width, height) {
        var canvas = this.canvas;
        var stage = this.stage;
        var style = canvas.style;

        canvas.width = width;
        canvas.height = height;

        style.width = stage.width * stage.scaleX + 'px';
        style.height = stage.height * stage.scaleY + 'px';
    }

});